001 /* 002 * Copyright 2004-2005 Stephen J. McConnell. 003 * Copyright 2004 Niclas Hedhman 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 013 * implied. 014 * 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 019 package net.dpml.transit.artifact; 020 021 import java.io.IOException; 022 import java.io.PrintWriter; 023 024 import java.net.URL; 025 import java.net.URLConnection; 026 import java.net.URLStreamHandler; 027 import java.security.AccessController; 028 import java.security.PrivilegedAction; 029 030 import net.dpml.transit.Transit; 031 import net.dpml.transit.TransitRuntimeException; 032 import net.dpml.transit.SecuredTransitContext; 033 034 /** 035 * The artifact URL protocol handler. 036 * @author <a href="http://www.dpml.net">Digital Product Meta Library</a> 037 * @version 1.0.2 038 */ 039 public class Handler extends URLStreamHandler 040 { 041 // ------------------------------------------------------------------------ 042 // static 043 // ------------------------------------------------------------------------ 044 045 /** 046 * Default buffer size. 047 */ 048 private static final int BUFFER_SIZE = 100; 049 050 // ------------------------------------------------------------------------ 051 // state 052 // ------------------------------------------------------------------------ 053 054 /** 055 * The transit context. 056 */ 057 private SecuredTransitContext m_context; 058 059 // ------------------------------------------------------------------------ 060 // constructor 061 // ------------------------------------------------------------------------ 062 063 /** 064 * Creation of a new transit artifact protocol handler. 065 */ 066 public Handler() 067 { 068 try 069 { 070 Transit.getInstance(); 071 m_context = SecuredTransitContext.getInstance(); 072 } 073 catch( RuntimeException e ) 074 { 075 e.printStackTrace(); 076 throw e; 077 } 078 } 079 080 // ------------------------------------------------------------------------ 081 // implementation 082 // ------------------------------------------------------------------------ 083 084 /** 085 * Opens a connection to the specified URL. 086 * 087 * @param url A URL to open a connection to. 088 * @return The established connection. 089 * @throws IOException If a connection failure occurs. 090 */ 091 protected URLConnection openConnection( final URL url ) 092 throws IOException 093 { 094 return new ArtifactURLConnection( url, m_context ); 095 } 096 097 /** 098 * Return the external representation of the supplied url. 099 * @param u the url 100 * @return a string representing of the url as an artifact uri 101 */ 102 protected String toExternalForm( URL u ) 103 { 104 StringBuffer buf = new StringBuffer( BUFFER_SIZE ); 105 buf.append( u.getProtocol() ); 106 buf.append( ":" ); 107 String path = getRealPath( u ); 108 if( path != null ) 109 { 110 int lastPos = path.length() - 1; 111 if( path.charAt( lastPos ) == '/' ) 112 { 113 buf.append( path.substring( 0, lastPos ) ); 114 } 115 else 116 { 117 buf.append( path ); 118 } 119 } 120 121 String internal = getInternalPath( u ); 122 if( null != internal ) 123 { 124 buf.append( internal ); 125 } 126 127 String query = u.getQuery(); 128 if( query != null ) 129 { 130 buf.append( '?' ); 131 buf.append( query ); 132 } 133 134 String version = u.getUserInfo(); 135 if( ( version != null ) && !"".equals( version ) ) 136 { 137 buf.append( '#' ); 138 buf.append( version ); 139 } 140 String result = buf.toString(); 141 buf.setLength( 0 ); 142 return result; 143 } 144 145 /** 146 * Return the pure artifact path without any internal address. 147 * @param url the url to evaluate 148 * @return the pure path 149 */ 150 private String getRealPath( URL url ) 151 { 152 String path = url.getPath(); 153 if( null == path ) 154 { 155 return null; 156 } 157 int index = path.indexOf( "!" ); 158 if( index < 0 ) 159 { 160 return path; 161 } 162 else 163 { 164 return path.substring( 0, index ); 165 } 166 } 167 168 /** 169 * Return the value of an internal address associated with a path. 170 * @param url the url to evaluate 171 * @return the internal address of null if the url does not contain an internal address 172 */ 173 private String getInternalPath( URL url ) 174 { 175 String path = url.getPath(); 176 if( null == path ) 177 { 178 return null; 179 } 180 int index = path.indexOf( "!" ); 181 if( index < 0 ) 182 { 183 return null; 184 } 185 else 186 { 187 return path.substring( index ); 188 } 189 } 190 191 192 /** 193 * Parse the supplied specification. 194 * @param dest the destination url to populate 195 * @param spec the supplied spec 196 * @param start the starting position 197 * @param limit the limit 198 */ 199 protected void parseURL( final URL dest, String spec, int start, int limit ) 200 { 201 try 202 { 203 final String protocol = dest.getProtocol(); 204 String specPath = spec.substring( start, limit ); 205 String path = dest.getPath(); 206 207 // get any query info from the supplied spec 208 209 final String query = getQueryFragment( specPath ); 210 if( null != query ) 211 { 212 int n = specPath.indexOf( "?" ); 213 if( n > -1 ) 214 { 215 specPath = specPath.substring( 0, n ); 216 } 217 } 218 219 // get the version using the url ref semantics 220 221 final String version = getRefFragment( specPath ); 222 if( null != version ) 223 { 224 int n = specPath.indexOf( "#" ); 225 if( n > -1 ) 226 { 227 specPath = specPath.substring( 0, n ); 228 } 229 } 230 231 // setup the path 232 233 if( path == null ) 234 { 235 path = specPath; 236 if( !path.endsWith( "/" ) && ( path.indexOf( "!" ) < 0 ) ) 237 { 238 path = path + "/"; 239 } 240 } 241 else 242 { 243 int lastPos = path.length() - 1; 244 if( path.charAt( lastPos ) == '/' ) 245 { 246 path = path.substring( 0, lastPos ); 247 } 248 if( specPath.charAt( 0 ) == '/' ) 249 { 250 path = path + "!" + specPath; 251 } 252 else 253 { 254 path = path + "!/" + specPath; 255 } 256 } 257 258 // establish the artifact type 259 260 String type = dest.getUserInfo(); 261 if( type == null ) 262 { 263 if( limit < spec.length() ) 264 { 265 type = spec.substring( limit + 1 ); 266 } 267 } 268 269 // map features to url fields 270 271 final String user = type; // final String user = version; 272 final String authority = null; 273 final int port = -1; 274 final String host = null; 275 final String ref = version; // final String ref = null; 276 final String finalPath = path; 277 AccessController.doPrivileged( 278 new PrivilegedAction() 279 { 280 public Object run() 281 { 282 setURL( dest, protocol, host, port, authority, user, finalPath, query, ref ); 283 return null; 284 } 285 } 286 ); 287 } 288 catch( Throwable e ) 289 { 290 try 291 { 292 PrintWriter log = Transit.getInstance().getLogWriter(); 293 String message = "Unable to parse the URL: " 294 + dest + ", " + spec + ", " + start + ", " + limit; 295 log.println( message ); 296 log.println( "---------------------------------------------------" ); 297 e.printStackTrace( log ); 298 } 299 catch( TransitRuntimeException f ) 300 { 301 f.printStackTrace(); 302 e.printStackTrace(); 303 } 304 } 305 } 306 307 private String getQueryFragment( String path ) 308 { 309 if( null == path ) 310 { 311 return null; 312 } 313 else 314 { 315 int q = path.indexOf( "?" ); 316 if( q > -1 ) 317 { 318 return path.substring( q+1 ); 319 } 320 else 321 { 322 return null; 323 } 324 } 325 } 326 327 private String getRefFragment( String path ) 328 { 329 if( null == path ) 330 { 331 return null; 332 } 333 else 334 { 335 int n = path.indexOf( "#" ); 336 if( n > -1 ) 337 { 338 return path.substring( n+1 ); 339 } 340 else 341 { 342 return null; 343 } 344 } 345 } 346 }